home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / Newton Platform Info / Newton 2.0 Sample Code / Desktop Connectivity / SoupDrink-2 / SoupDrink-Mac-2 / Engine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-12  |  21.4 KB  |  639 lines  |  [TEXT/R*ch]

  1. /*****************************************************************************************
  2.  * Engine.c                                                      
  3.  *
  4.  *    Written by:    Rob Langhorne, J. Christopher Bell, and David Fedor
  5.  * 
  6.  *    Copyright:    © 1995-1996 by Apple Computer, Inc.  All rights reserved.
  7.  *
  8.  * This file is used both by the Macintosh and Windows versions of SoupDrink; it contains
  9.  * nearly all the calls to the CDIL and FDIL code other than the initialization routines.
  10.  *
  11.  * SoupDrink() is the routine for soup drinking: uploading a soup to the desktop.
  12.  * UploadNewName() sends a frame holding a "name card" to the Newton.
  13.  * PrintEntry() and PrintTree() pretty-print the contents of a frame to a file.
  14.  * 
  15.  * Purpose:
  16.  *   To demonstrate the basic parts of FDILs and CDILs. The basic engines currently in
  17.  *   this code are the "soup drink" engine which uploads a Newton soup and the the
  18.  *   "new name" engine which downloads a business card to the Newton names database.
  19.  *   This sample can work over any transport, but the SoupDrink sample on the Newton
  20.  *   may use "spit" mode over ADSP (because of problems in OutputFrame() that used to
  21.  *   exist on Newton 1.x devices prior to the December 1995 patch).
  22.  *
  23.  *   The soup drinking is split into two sections to illustrate both synchronous and
  24.  *   asynchronous reading. The first entry read is done asynchronously from this
  25.  *   function, with the callback function SoupDrinkCallback (below) doing the rest of
  26.  *   the communication synchronously.
  27.  * 
  28.  *   The protocol for the soup drink is:
  29.  *      Newton                                                             Desktop
  30.  *      ======                                                             =======
  31.  *                                                                    <---- "DRNK"
  32.  *     "DRNK" or "SPIT" (depending whether sending frames is supported)-->
  33.  *     "ENTR"-->
  34.  *     a frame (or a string if in spit mode)--->
  35.  *                                                                    <---- "OK"
  36.  *     [then repeat with ENTR command, or ...]
  37.  *     "END "--> 
  38.  *       
  39.  */
  40.  
  41. #ifndef _windows
  42. #define forMac        // Codewarrior doesn't have a handy way to do this.
  43. #endif
  44.  
  45.  
  46. #include <string.h>
  47. #include <stdio.h>
  48.  
  49.  
  50. #ifdef forMac    // ****** stuff for MAC-OS applications ******
  51. #include <Types.h>
  52. #include <memory.h>
  53.  
  54. // In the beta 8 CW6 libraries, "MPW C Calling Conventions" needed to be turned on.
  55. // This does NOT need to be done any more, but I'm leaving in the comment so that
  56. // people realize the current situation.  This comment will self-destruct in 5 seconds.
  57. // #pragma mpwc on
  58. #include "DILCPIPE.h" 
  59. #include "HLFDIL.h"
  60. // #pragma mpwc reset
  61.  
  62. #include "SoupDrink.h"
  63. #define Timeout 600        // this is currently in ticks but should be in milliseconds
  64.  
  65.  
  66. #else           // ****** stuff for Windows applications *********
  67.  
  68. #include <windows.h>
  69. #include "DILCPIPE.H" 
  70. #include "HLFDIL.h"
  71. #include "SOUPDRNK.H"
  72. #define Timeout 20000    // time out in 20 seconds
  73. typedef unsigned char   Str255[256];
  74.  
  75. #define CurrentTimeInSeconds() ((long)(GetTickCount() / 1000))
  76.  
  77. #endif
  78.  
  79.  
  80.  
  81. #include "Engine.h"
  82. #define  kTimeoutInSecs 15
  83. #define Encoding 0
  84. #define Swapping 0
  85.  
  86. extern CDILPipe        *ourPipe;
  87. extern void            *gThisObject;        // This is the only DIL frame active at one time in this app
  88. extern int            gInputMode;            // drink mode (receive frames) or spit mode (receive strings)
  89. extern char            gReceivedString[];         // received string; used in 'spit mode'
  90. extern long            gReceivedStringLen;        // received string length (see above)
  91. extern char         gTempBuffer [256];        // a global string buffer for input dialogs, etc
  92.  
  93. CommErr SoupDrink() 
  94. {
  95.     char         soupName[255];
  96.     char         response[5];
  97.     long        length;
  98.     objErr        fErr = 0;
  99.     long        longLen;
  100.     Boolean        eom;
  101.     long        endTime;
  102.  
  103.     inputDialog((char *)soupName, "Names", "Enter Soup Name:");
  104.     if ('\0' == *soupName)        /*    Probably a cancel    */
  105.         return 0;
  106.     
  107.     if (strlen(soupName) > 253)
  108.         soupName[253] = 0;
  109.     strcat((char *)soupName, "\4");
  110.     
  111.     fErr = (short) InitializePipe();
  112.     if (fErr)
  113.         return fErr;        // don't need to dispose pipe if error
  114.  
  115.     // make the connection!
  116.     CHECKDILERROR((short) CDPipeListen(ourPipe, kDefaultTimeout, 0, 0));
  117. #ifndef _windows
  118.     CHECKDILERROR((short) CDPipeAccept(ourPipe));
  119. #else
  120.     // This code doesn't need to be done on the MacOS side, but is currently required
  121.     // for Windows.  You need to loop a little bit for the connection state to be
  122.     // set to kCDIL_ConnectPending.  It might not do that if there's nobody on the
  123.     // other side of the cable, though!
  124.  
  125.     // Loop until the Newton device connects
  126.     endTime = CurrentTimeInSeconds() + kTimeoutInSecs;    // time at which we should stop looping
  127.     while (CurrentTimeInSeconds() < endTime) {
  128.         if (CDGetPipeState(ourPipe) == kCDIL_ConnectPending) {
  129.             CHECKDILERROR((short) CDPipeAccept(ourPipe));
  130.             break;
  131.         } else
  132.             CDIdle(ourPipe);
  133.     }
  134.  
  135.     if (CurrentTimeInSeconds() >= endTime) {    // did we time out?
  136.         CDPipeDisconnect(ourPipe) ;
  137.         return kOurTimeoutError;
  138.     }
  139. #endif        
  140.  
  141.     /*    Initiate conversation; tell the Newton that we want to do a 'DRNK' */
  142.     length = 4;
  143.     CHECKDILERROR((short) CDPipeWrite(ourPipe, (void *)"DRNK", &length, true,Swapping,Encoding,Timeout,0,0));
  144.     
  145.     /* send the name of the soup we want to search */
  146.     length = strlen(soupName);
  147.     CHECKDILERROR((short) CDPipeWrite(ourPipe, (void *)soupName, &length, true,Swapping,Encoding,Timeout,0,0));
  148.     
  149.     /* get the Newton response. Possibilities are:
  150.      *   "DRNK"  -- no problem; about to begin
  151.      *   "SPIT"  -- DRNK not supported.   ADSP and outputframe is a problem on some systems -
  152.      *              that is, 1.x Newton devices without the December 1995 system update (xxx333).
  153.      *              The Newton will spit strings representing the names. In this case,
  154.      *              you might want to 'flatten' the frames yourself using the CDILs but not FDILS.
  155.      *   "NONE"  -- that soup is not available.
  156.      */
  157.     length = 4;
  158.     CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
  159.     response[4] = 0;
  160.     if (strcmp(response, "DRNK") == 0)
  161.         gInputMode = kDrinkMode;
  162.     else if (strcmp(response, "SPIT") == 0)
  163.         gInputMode = kSpitMode;
  164.     else if (strcmp(response, "NONE") == 0) {
  165.         PostAlertMessage("Could not open that soup on Newton.", "", "", "");
  166.         CDPipeDisconnect(ourPipe);
  167.         return(0);
  168.         }
  169.         
  170.     length = 4;
  171.     
  172.     /* receive a response; "END " for no more entries, "ENTR" for another soup entry */
  173.     CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
  174.     
  175.     response[4] = 0;                        /* make it a c string */
  176.     if (strcmp(response, "END ") == 0) {    /* if there are no more entries */
  177.         CDPipeDisconnect(ourPipe);
  178.         PostAlertMessage("At end...", "", "", "");
  179.         return(0);
  180.         }
  181.     if (strcmp(response, "ENTR") != 0) {
  182.         PostAlertMessage("Received unknown command:", response, "", "");
  183.         CDPipeDisconnect(ourPipe);
  184.         return(0);
  185.         }
  186.  
  187.     /*    read frame as unbound data    */
  188.     gThisObject = FDCreateObject(kDILFrame, nil);
  189.  
  190.     gReceivedStringLen = kMAXSTR;
  191.     longLen = 4;
  192.     if (gInputMode == kDrinkMode) {
  193.         fErr = (short) FDget(gThisObject, kDILFrame, ourPipe, Timeout, (CDILPipeCompletionProcPtr)SoupDrinkCallback, 0);
  194.     } else {
  195.         // we're in "spit" mode; the newton says it can't send frames.
  196.         fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedStringLen, &longLen, &eom,Swapping,Encoding,Timeout,0,0);
  197.         if (fErr == 0)
  198.             fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedString[0], &gReceivedStringLen, &eom,
  199.                                         Swapping,Encoding,Timeout,(CDILPipeCompletionProcPtr)SoupDrinkCallback, 0);
  200.     }
  201.         
  202.     if (fErr) {
  203.         CDPipeDisconnect(ourPipe);
  204.         PostAlertMessage("Read returned",ErrorStrings(fErr, gTempBuffer) ,"", "");
  205.         return 0;
  206.         }
  207.  
  208.     return fErr;    
  209. }
  210.  
  211.  
  212. /********************************************************************************
  213.  * SoupDrinkCallback
  214.  *
  215.  * SoupDrinkCallback is the drinking soup 'read' callback function
  216.  */
  217. /* for 16 bit Windows... void FAR _loadds  */
  218. #ifdef forWin16
  219. void FAR _loadds SoupDrinkCallback (CommErr errorValue, void *pData, Size Count, long refCon, long lFlags)
  220. #else
  221. static void      SoupDrinkCallback (CommErr errorValue, void *pData, Size Count, long refCon, long lFlags)
  222. #endif 
  223. {
  224.     FILE             *fp;        /* file reference */
  225.     slotDefinition *list = nil;
  226.     long            fErr = 0, len = 3;
  227.     long            longLen;
  228.     long            length;
  229.     char             response[255];
  230.     Boolean            eom;
  231.     short            x;
  232.  
  233.     if (errorValue)
  234.     {
  235.         Str255 refConStr;
  236.     
  237.         sprintf((char*) refConStr, "%d", Count);
  238.         PostAlertMessage("Read returns:", (char*) refConStr, ". Error: ", 
  239.                 ErrorStrings(errorValue, gTempBuffer));
  240.         return;
  241.     }
  242.     
  243.     /*    open file for entry (append)        */
  244.     fp = fopen("SoupData.out", "w+");
  245.     if (!fp)
  246.     {
  247.         PostAlertMessage("Could not open file", "", "", "");
  248.         return;
  249.     }
  250.     
  251.     do {    /*    traverse frames        */
  252.         if (gInputMode == kSpitMode) /* we are just receiving strings, not frames */
  253.             {
  254.             gReceivedString[gReceivedStringLen] = 0;    /* turn it into c string */
  255.             fprintf(fp, gReceivedString);                /* send the string to the file */
  256.             fprintf(fp, "\n");                            /* send a carriage return char */
  257.             }
  258.         else
  259.             {        
  260.                 
  261.             /*    We should have an unbound frame    list */
  262.             list = FDGetUnboundList(gThisObject);    
  263.             if (!list)                            /* if not, we got an empty soup frame?; fail! */
  264.                 break;
  265.                 
  266.             /*    traverse list        */
  267.             for (x= 0; x < list->peerCnt; x++)
  268.                 printTree(fp, &list[x], 1);
  269.     
  270.             fputc('\n', fp);
  271.             fputc('\n', fp);
  272.             fputc('\n', fp);
  273.     
  274.             FDFreeUnboundList(gThisObject, list);    
  275.             list = nil;
  276.             }
  277.             
  278.         if (fErr)
  279.                 PostAlertMessage("Unboundlist stuff returns:", ErrorStrings(fErr, gTempBuffer), "", "");
  280.         else
  281.         {
  282.             /*    read next frame    */
  283.             
  284.             len = 3;
  285.             fErr = CDPipeWrite(ourPipe, (void *)"OK\4", &len, true,Swapping,Encoding,Timeout,0,0) ; /* acknowledge receipt! */
  286.             if (!fErr)
  287.             {
  288.             length = 4;
  289.             
  290.             /* receive a response; "END " for no more entries, "ENTR" for another soup entry */
  291.             fErr = (short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0);
  292.             if (fErr)
  293.                 {
  294.                 PostAlertMessage("Read returns:",ErrorStrings(fErr, gTempBuffer) ,"", "");
  295.                 return;
  296.                 }
  297.                 
  298.             response[4] = 0;                        /* make it a c string */
  299.             if (strcmp(response, "END ") == 0) {    /* if there are no more entries */
  300.                 CDPipeDisconnect(ourPipe);
  301.                 break;
  302.                 }
  303.             if (strcmp(response, "ENTR") != 0) {
  304.                 PostAlertMessage("Received unknown command: ", response, "", "");
  305.                 break;
  306.                 }
  307.             gReceivedStringLen = kMAXSTR;
  308.             longLen = 4; 
  309.     
  310.             if (gInputMode == kDrinkMode)
  311.                 fErr = FDget(gThisObject, kDILFrame, ourPipe, 500*60, 0, 0);
  312.             else {
  313.                 fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedStringLen, &longLen, &eom,Swapping,Encoding,Timeout,0,0);
  314.                 fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedString[0], &gReceivedStringLen, &eom,Swapping,Encoding,Timeout,0,0);
  315.                 }
  316.             }
  317.         }        
  318.     } while (!fErr && gThisObject);
  319.     
  320.  
  321.     /* Clean up */
  322.     if (fErr)
  323.         PostAlertMessage("At end of soupdrink: ", ErrorStrings(fErr, gTempBuffer), "", "");
  324.     
  325.     fflush(fp);        
  326.     if (list)
  327.         FDFreeUnboundList(gThisObject, list);
  328.     fclose(fp);
  329.     FDDisposeObject(gThisObject);
  330.     CDPipeDisconnect(ourPipe);
  331. }
  332.  
  333.  
  334.  
  335.  
  336. /*
  337.  * UploadNewName
  338.  *
  339.  * This function connects to a Newton and sends it a "name" for the names application.
  340.  */
  341. CommErr UploadNewName ()
  342. {
  343.     CommErr        fErr = 0;
  344.     void        *entry, *name;
  345.     void        *phones;
  346.     long        cardType = 4, len;
  347.     char        pClass[] = "person";
  348.     char        fName[] = "Howard";
  349.     char        lName[] = "Duck";
  350.     char        phoneNo[] = "555-1212";
  351.     char         addr[]    = "123 Sesame Street";
  352.     char        town[] = "Anytown";
  353.     char        state[] = "CA";
  354.     char        zip[] = "95014";
  355.     char        sName[] = "Duck";
  356.     char         response[5];
  357.     long        length;
  358.     Boolean        eom;
  359.     long        endTime;
  360.     
  361.     
  362.     fErr = (short) InitializePipe();
  363.     if (fErr)
  364.         return fErr;    // don't need to dispose pipe if error
  365.  
  366.     // make the connection!
  367.     CHECKDILERROR((short) CDPipeListen(ourPipe, kDefaultTimeout, 0, 0 ) );
  368. #ifndef _windows
  369.     CHECKDILERROR((short) CDPipeAccept(ourPipe));
  370. #else
  371.     // This code doesn't need to be done on the MacOS side, but is currently required
  372.     // for Windows.  You need to loop a little bit for the connection state to be
  373.     // set to kCDIL_ConnectPending.  It might not do that if there's nobody on the
  374.     // other side of the cable, though!
  375.  
  376.     // Loop until the Newton device connects
  377.     endTime = CurrentTimeInSeconds() + kTimeoutInSecs;    // time at which we should stop looping
  378.     while (CurrentTimeInSeconds() < endTime) {
  379.         if (CDGetPipeState(ourPipe) == kCDIL_ConnectPending) {
  380.             CHECKDILERROR((short) CDPipeAccept(ourPipe));
  381.             break;
  382.         } else
  383.             CDIdle(ourPipe);
  384.     }
  385.  
  386.     if (CurrentTimeInSeconds() >= endTime) {    // did we time out?
  387.         CDPipeDisconnect(ourPipe) ;
  388.         return kOurTimeoutError;
  389.     }
  390. #endif
  391.  
  392.     /*    Create an object        */
  393.  
  394.     // in the future, errors should delete name, phones, entry objects.
  395.     
  396.     name = FDCreateObject(kDILFrame, NULL);    
  397.     CHECKDILERROR((short) FDbindSlot(name, "Class", (void *)&pClass, kDILSymbol, strlen(pClass), -1, NULL));
  398.     CHECKDILERROR((short) FDbindSlot(name, "first", (void *)&fName, kDILString, strlen(fName), -1, NULL));
  399.     CHECKDILERROR((short) FDbindSlot(name, "last", (void *)&lName, kDILString, strlen(lName), -1, NULL));
  400.  
  401.     phones = FDCreateObject(kDILArray, NULL);
  402.     CHECKDILERROR((short) FDbindSlot(phones, "HomePhone", (void *)&phoneNo, kDILString, strlen(phoneNo), -1, NULL));
  403.  
  404.     entry = FDCreateObject(kDILFrame, NULL);
  405.     CHECKDILERROR((short) FDbindSlot(entry, "cardType", (void *)&cardType, kDILInteger, sizeof(int), -1, NULL)) ;
  406.     CHECKDILERROR((short) FDbindSlot(entry, "Name", (void *)name, kDILFrame, 0, -1, NULL));
  407.     CHECKDILERROR((short) FDbindSlot(entry, "Address", (void *)&addr, kDILString, strlen(addr), -1, NULL)) ;
  408.     CHECKDILERROR((short) FDbindSlot(entry, "City", (void *)&town, kDILString, strlen(town), -1, NULL)) ;
  409.     CHECKDILERROR((short) FDbindSlot(entry, "Region", (void *)&state, kDILString, strlen(state), -1, NULL)) ;
  410.     CHECKDILERROR((short) FDbindSlot(entry, "Postal_Code", (void *)&zip, kDILString, strlen(zip), -1, NULL)) ;
  411.     CHECKDILERROR((short) FDbindSlot(entry, "phones", (void *)phones, kDILArray, 0, -1, NULL)) ;                        
  412.     CHECKDILERROR((short) FDbindSlot(entry, "sorton", (void *)&sName, kDILString, strlen(sName), 0, "Name")) ;    
  413.  
  414.     /*    Initiate conversation    */
  415.     len = 5;
  416.     CHECKDILERROR((short) CDPipeWrite (ourPipe, (void *)"NAME\4", &len, true, Swapping,Encoding,Timeout, 0, 0)) ;
  417.     
  418.     /*    Send a frame        */
  419.     CHECKDILERROR((short) FDput(entry, kDILFrame, ourPipe)) ;
  420.     
  421.     FDDisposeObject(phones);
  422.     FDDisposeObject(name);
  423.     FDDisposeObject(entry);
  424.     
  425.     // wait for the ack back from the Newton (or for 30 seconds) before we disconnect
  426.     length = 2;
  427.     CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
  428.  
  429.     CDPipeDisconnect(ourPipe) ;
  430.     
  431.     return fErr;    
  432.  
  433. }
  434.  
  435.  
  436.  
  437.  
  438. void    printEntry (FILE * fp, slotDefinition *thisEntry)
  439. {    
  440.     if (thisEntry->slotName)
  441.         fprintf( fp, "%s : ", thisEntry->slotName);
  442.     
  443.     switch (thisEntry->varType)
  444.     {
  445.         case kDILCharacter:            /*    ASCII Character                    */
  446.             fprintf( fp, "'%c'\n", *(char *)thisEntry->var);
  447.             break;
  448.             
  449.         case kDILUnicodeCharacter:    /*    Unicode Character                */
  450.             {
  451.                 char c = *(((char *)thisEntry->var)+1);
  452.                 fprintf( fp,  "$%c\n", (char *)c);
  453.             }
  454.             break;
  455.             
  456.         case kDILString:            /*    String (null-terminated)        */
  457.             if (thisEntry->oClass)
  458.                 // there's a special class defined for this string; show it.
  459.                 fprintf( fp, "\"%s\" (class '%s)\n", (char *)thisEntry->var, (char *)thisEntry->oClass);
  460.             else
  461.                 // generic string; no special class.
  462.                 fprintf( fp,  "\"%s\"\n", (char *)thisEntry->var);
  463.             break;
  464.             
  465.         case kDILBoolean:            /*    Boolean                            */
  466.             if (*(Boolean *)thisEntry->var)
  467.                 fprintf( fp,  "TRUE\n");
  468.             else
  469.                 fprintf( fp,  "FALSE\n");
  470.             break;
  471.             
  472.         case kDILImmediate:            /*    Indeterminate Immediate type    */
  473.         case kDILInteger:            /*    Integer (4 byte)                */
  474.             fprintf( fp, "#%ld\n", *(long *)thisEntry->var);
  475.             break;
  476.             
  477.         case kDILPlainArray:        /*    Anonymous Array                    */
  478.             fprintf (fp, "PLAINARRAY\n");
  479.             break;
  480.             
  481.         case kDILArray:                /*    Named Array                        */
  482.             if (thisEntry->oClass)
  483.                 fprintf (fp, "NAMEDARRAY (class '%s)\n", thisEntry->oClass);
  484.             else
  485.                 fprintf (fp, "NAMEDARRAY (No class???)\n");
  486.             break;
  487.         
  488.         case kDILFrame:                /*    Frame                            */
  489.             fprintf (fp, "FRAME \n");
  490.             break;
  491.         
  492.         case kDILSmallRect:            /*    Small rect                        */
  493.             fprintf (fp, "SMALLRECT\n");
  494.             break;
  495.         
  496.         case kDILPrecedent:            /*    Repeated Item                    */
  497.             fprintf (fp, "PRECEDENT %s\n", (char *)thisEntry->var);
  498.             break;
  499.         
  500.         case kDILSymbol:            /*    Object Symbol                    */
  501.             fprintf( fp,  "'%s\n", (char *)thisEntry->var);
  502.             break;
  503.         
  504.         case kDILBinaryObject:        /*    Small Binary Object ( < 32K )    */
  505.             if (thisEntry->oClass)
  506.                 if (0==strcmp(thisEntry->oClass,"Real")) {
  507.                     double tmpDouble;
  508. #ifdef _windows
  509.                     // ieee reals have bytes in the opposite order...
  510.                     unsigned long tmpWord1;
  511.                     unsigned long tmpWord2;
  512.                     tmpWord1 = ((unsigned long *)thisEntry->var)[0];
  513.                     tmpWord2 = ((unsigned long *)thisEntry->var)[1];
  514.                     tmpWord1 =  ((tmpWord1 & 0x000000ff) << 24) |
  515.                                 ((tmpWord1 & 0x0000ff00) <<  8) |
  516.                                 ((tmpWord1 & 0x00ff0000) >>  8) |
  517.                                 ((tmpWord1 & 0xff000000) >> 24);
  518.                     tmpWord2 =  ((tmpWord2 & 0x000000ff) << 24) |
  519.                                 ((tmpWord2 & 0x0000ff00) <<  8) |
  520.                                 ((tmpWord2 & 0x00ff0000) >>  8) |
  521.                                 ((tmpWord2 & 0xff000000) >> 24);
  522.                     ((unsigned long *)&tmpDouble)[0] = tmpWord2;
  523.                     ((unsigned long *)&tmpDouble)[1] = tmpWord1;
  524. #else
  525.                     tmpDouble = *(double *)thisEntry->var;
  526. #endif
  527.                     fprintf( fp,  "%f\n", tmpDouble);
  528.                 }
  529.                 else
  530.                     fprintf( fp,  "<%s, length %ld>\n", thisEntry->oClass, (ulong *) thisEntry->length);
  531.             else
  532.                 fprintf( fp,  "<binary, length %ld>\n", (ulong *) thisEntry->length);
  533.             break;
  534.         
  535.         case kDILNIL:                /*    nil object                        */
  536.             fprintf (fp, "NIL\n");
  537.             break;
  538.         
  539.         case kDILBLOB:                /*    Large Binary Object                */
  540.             fprintf (fp, "BLOB\n");
  541.             break;
  542.         
  543.         default:                    // ~~~~~ ignore these
  544.             fprintf (fp, "UNKNOWN TYPE\n");
  545.             break;
  546.     }
  547. }
  548.  
  549. //========================================================================================
  550. // printTree
  551.  
  552. // printTree pretty prints the output, traversing the simple "tree" of data
  553. //========================================================================================
  554. void printTree (FILE * fp, slotDefinition *thisEntry, short depth)
  555. {
  556.     short i;
  557.     short y;
  558.     
  559.     for (i = 0; i < depth; i++)
  560.         fputc('\t', fp);
  561.         
  562.     printEntry(fp, thisEntry);
  563.     
  564.     if (thisEntry->children)
  565.         for (y= 0; y < thisEntry->childCnt; y++)
  566.             printTree(fp, &(thisEntry->children[y]), depth + 1);
  567. }
  568.  
  569.  
  570. /* ErrorStrings
  571.  * 
  572.  * Purpose: return error string based on error number from the CDIL or FDIL
  573.  */
  574. char* ErrorStrings(CommErr theErr, char* theString)
  575. {
  576.     switch (theErr)
  577.         {
  578.         case kOurTimeoutError:  strcpy((char*) theString, 
  579.             (char*) "Timeout error. (Determined by SoupDrink)"); break;
  580.         case -97:  strcpy((char*) theString, 
  581.             (char*) "The port is busy. Quit the relevant application or restart if necessary (from ATalk Driver)");  break;
  582.  
  583.         // CDIL errors (see DILCPipe.h)
  584.         case -28701:  strcpy((char*) theString, 
  585.             (char*) "Error on memory allocation.");  break;
  586.         case -28702:  strcpy((char*) theString, 
  587.             (char*) "DIL pipe was set to a bad state.");  break;
  588.         case -28703:  strcpy((char*) theString, 
  589.             (char*) "An unknown exception has occurred.");  break;
  590.         case -28704:  strcpy((char*) theString, 
  591.             (char*) "The queue of asynchronous calls is full.");  break;
  592.         case -28705:  strcpy((char*) theString, 
  593.             (char*) "Pipe has not been initialized.");  break;
  594.         case -28706:  strcpy((char*) theString, 
  595.             (char*) "Parameter passed in was invalid.");  break;
  596.         case -28707:  strcpy((char*) theString, 
  597.             (char*) "Pipe is not ready for operation.");  break;
  598.         case -28708:  strcpy((char*) theString, 
  599.             (char*) "Timeout during DIL operation.");  break;
  600.  
  601.         // FDIL errors (see HLFDIL.h)
  602.         case -28801:  strcpy((char*) theString, 
  603.             (char*) "Out of heap memory");  break;
  604.         case -28802:  strcpy((char*) theString, 
  605.             (char*) "Out of temporary or other memory");  break;
  606.         case -28803:  strcpy((char*) theString, 
  607.             (char*) "Unknown slot");  break;
  608.         case -28804:  strcpy((char*) theString, 
  609.             (char*) "Slot size exceeded");  break;
  610.         case -28805:  strcpy((char*) theString, 
  611.             (char*) "Slot size is required");  break;
  612.         case -28806:  strcpy((char*) theString, 
  613.             (char*) "Unexpected data type");  break;
  614.  
  615.         // other errors
  616.         case -28003:  strcpy((char*) theString, 
  617.             (char*) "The communication operation was aborted.");  break;
  618.         case -28009:  strcpy((char*) theString, 
  619.             (char*) "Bad connection detected");  break;
  620.         case -28017:  strcpy((char*) theString, 
  621.             (char*) "Out of memory");  break;
  622.         case -28029:  strcpy((char*) theString, 
  623.             (char*) "Cannot connect to modem; no response.");  break;
  624.         case -28030:  strcpy((char*) theString, 
  625.             (char*) "Disconnection detected.");  break;
  626.         case -28100:  strcpy((char*) theString, 
  627.             (char*) "Disconnect occurred while reading.");  break;
  628.         case -28101:  strcpy((char*) theString, 
  629.             (char*) "An error occurred while reading.");  break;
  630.         case -28102:  strcpy((char*) theString, 
  631.             (char*) "The communication tool was not found");  break;
  632.         case -28103:  strcpy((char*) theString, 
  633.             (char*) "Bad modem tool version");  break;
  634.         default: sprintf(theString, "%ld", theErr);
  635.         }
  636.     return (char*) theString;
  637. }
  638.  
  639.